/*
 * Copyright (C) 2011 Benoit GUEROUT <bguerout at gmail dot com> and Yves AMSELLEM <amsellem dot yves at gmail dot com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kerbores.jongo;

import java.util.List;

import org.nutz.lang.Lang;

import com.kerbores.jongo.bson.BsonDBDecoder;
import com.kerbores.jongo.bson.BsonDBEncoder;
import com.kerbores.jongo.marshall.nutz.NutzMapper;
import com.kerbores.jongo.marshall.nutz.NutzMarshallerEngine;
import com.kerbores.jongo.query.Query;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;

public class Jongo {

	private final DB database;
	private final Mapper mapper;

	public Jongo(DB database) {
		this(database, NutzMapper.create(new NutzMarshallerEngine()));
	}

	@SuppressWarnings({ "resource", "deprecation" })
	protected Jongo(String host, int port, String db) {
		this(new JongoClient(host, port).getDB(db), NutzMapper.create(new NutzMarshallerEngine()));
	}

	/**
	 * client创建
	 * 
	 * @param client
	 *            mongoclient
	 * @param db
	 *            数据库
	 * @return Jongo
	 */
	public static Jongo me(MongoClient client, String db) {
		return new Jongo(db(client, db));
	}

	/**
	 * 简便链接
	 * 
	 * @param host
	 *            主机
	 * @param database
	 *            数据库
	 * @return Jongo
	 */
	public static Jongo me(String host, String database) {
		return me(host, ServerAddress.defaultPort(), database);
	}

	/**
	 * 单机无密码
	 * 
	 * @param host
	 *            主机
	 * @param port
	 *            端口
	 * @param db
	 *            数据库
	 * @return Jongo
	 */
	public static Jongo me(String host, int port, String db) {
		return new Jongo(host, port, db);
	}

	/**
	 * 单机有密码
	 * 
	 * @param userName
	 *            用户名
	 * @param password
	 *            密码
	 * @param host
	 *            主机
	 * @param port
	 *            端口
	 * @param database
	 *            数据库
	 * @return Jongo
	 */
	public static Jongo me(String userName, String password, String host, int port, String database) {
		return new Jongo(db(client(userName, password, host, port, database), database));
	}

	@SuppressWarnings("deprecation")
	protected static DB db(MongoClient client, String db) {
		return client.getDB(db);
	}

	public static ServerAddress NEW_SA(String host, int port) {
		return new ServerAddress(host, port <= 0 ? ServerAddress.defaultPort() : port);
	}

	public static JongoClient client() {
		return client("localhost", ServerAddress.defaultPort());
	}

	public static JongoClient client(String host) {
		return client(host, ServerAddress.defaultPort());
	}

	public static JongoClient client(String host, int port) {
		return new JongoClient(host, port);
	}

	public static JongoClient client(ServerAddress sa, MongoCredential cred) {
		return client(sa, cred, null);
	}

	public static JongoClient client(ServerAddress sa, MongoCredential cred, MongoClientOptions mopt) {
		return new JongoClient(sa == null ? null : Lang.list(sa), cred == null ? null : Lang.list(cred), mopt);
	}

	public static JongoClient client(List<ServerAddress> sas, List<MongoCredential> creds, MongoClientOptions mopt) {
		return new JongoClient(sas, creds, mopt);
	}

	public static MongoClient client(String userNaclient, String password, String host, int port) {
		return client(userNaclient, password, host, port, null);
	}

	public static JongoClient client(String userName, String password, String host, int port, String database) {
		return client(NEW_SA(host, port), MongoCredential.createMongoCRCredential(userName, database, password.toCharArray()));
	}

	public Jongo(DB database, Mapper mapper) {
		this.database = database;
		this.mapper = mapper;
	}

	public MongoCollection getCollection(String name) {
		DBCollection dbCollection = database.getCollection(name);
		dbCollection.setDBDecoderFactory(BsonDBDecoder.FACTORY);
		dbCollection.setDBEncoderFactory(BsonDBEncoder.FACTORY);
		return new MongoCollection(dbCollection, mapper);
	}

	public DB getDatabase() {
		return database;
	}

	public Mapper getMapper() {
		return mapper;
	}

	public Query createQuery(String query, Object... parameters) {
		return mapper.getQueryFactory().createQuery(query, parameters);
	}

	public Command runCommand(String query) {
		return runCommand(query, new Object[0]);
	}

	public Command runCommand(String query, Object... parameters) {
		return new Command(database, mapper.getUnmarshaller(), mapper.getQueryFactory(), query, parameters);
	}
}
